package Screens 
{
	import DeviceData.LocalDB;
	import ExternalService.ApiConnection;
	import feathers.controls.Button;
	import feathers.controls.Header;
	import feathers.controls.Label;
	import feathers.controls.PickerList;
	import feathers.controls.ProgressBar;
	import feathers.controls.Screen;
	import feathers.controls.ScrollContainer;
	import feathers.controls.Scroller;
	import feathers.controls.TabBar;
	import feathers.controls.TextInput;
	import feathers.data.ListCollection;
	import feathers.events.FeathersEventType;
	import feathers.layout.VerticalLayout;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.PixelSnapping;
	import flash.events.HTTPStatusEvent;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.MediaEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.geom.Matrix;
	import flash.media.CameraRoll;
	import flash.media.MediaPromise;
	import flash.utils.ByteArray;
	import flash.utils.IDataInput;
	import Media.ExtendedMetalWorksMobileTheme;
	import starling.display.DisplayObject;
	import starling.display.Image;
	import starling.events.Event;
	import starling.textures.Texture;
	import starling.display.Sprite;
	/**
	 * @author Simon Claeye
	 * @version 2.0
	 */
	public class GalleryScreen extends Screen
	{
		private var database:LocalDB;
		private var loaderArray:Array = new Array();
		private var selectionArray:Array = new Array();
		private var imageData:Array;
		
		//Util
		private var tabBar:TabBar;
		private var statusLabel:Label;
		private var statusChange:Boolean = false;
		private var selectImageButton:Button;
		private var selectImageAdded:Boolean = false;
		private var imageDatabaseData:Array;
		
		//Edit image vars
		private var editContainer:ScrollContainer;
		private var editConainerAdded:Boolean = false;
		private var notesIn:TextInput;
		private var tagsIn:TextInput;
		private var editData:Object;
		
		//Upload image vars
		private var imagePromise:MediaPromise
		private var dataSource:IDataInput;
		private var tempDir;
		private var uploadContainer:ScrollContainer;
		private var imageNativePath:String;
		private var uploadContainerAdded:Boolean = false;
		private var connection:ApiConnection;
		private var token:String;
		private var excursionArray:Array;
		private var excursionPicker:PickerList;
		private var outcropPicker:PickerList
		private var outcropPickerAdded:Boolean = false;
		private var excursionLabel:Label;
		private var eLabelAdded:Boolean = false;
		private var outcropArray:Array;
		private var excursionIndex:int;
		private var excursionItems:Array;
		private var outcropItems:Array;
		private var currentExcursion:int;
		private var progressBar:ProgressBar;
		private var progressBarAdded:Boolean = false;
		private var progressBarLabel:Label;
		private var currentExcursionOutcrops:Array;
		
		/**
		 * 	The constructor.
		 * @param	database the database to be used by the screen
		 */
		public function GalleryScreen(database:LocalDB=null) 
		{
			this.database = database;
			this.addEventListener( Event.ADDED_TO_STAGE, addedToStageHandler );
		}
		
		private function addedToStageHandler(event:Event):void
		{
			// handles the back and menu hardware keys on android
			this.backButtonHandler = backHandler;
			this.menuButtonHandler = menuHandler;

			//create the uploadContainer
			drawUploadContainer();
			drawEditContainer();		
			
			//Draw header bar
			var header:Header = new Header();
			this.addChild(header);
			
			var backButton:Button = new Button();
			backButton.label = "Main Menu";
			backButton.addEventListener(Event.TRIGGERED, backHandler);
			
			//add back button to header
			header.leftItems = new <DisplayObject>[ backButton ];
			header.setSize((this.stage.stageWidth), (this.stage.stageHeight / 10));
			header.validate();
			
			//create error label, using the input label text format
			statusLabel = new Label();
			statusLabel.nameList.add(ExtendedMetalWorksMobileTheme.INPUT_LABEL);
			statusLabel.x = 10;
			statusLabel.y = (this.stage.stageHeight / 10) + 20;
			
			//Get image data from the local database
			imageDatabaseData = database.readImageData();
			
			//create select image button
			selectImageButton = new Button();
			selectImageButton.nameList.add(ExtendedMetalWorksMobileTheme.MENU_BUTTON);			
			selectImageButton.label = "Select Image";
			
			selectImageButton.x = (this.stage.stageWidth / 8);
			selectImageButton.y = (this.stage.stageHeight / 8) + 2*(this.stage.stageHeight / 8);
			selectImageButton.setSize(((this.stage.stageWidth / 4) * 3), this.stage.stageHeight / 10);
			
			selectImageButton.addEventListener(Event.TRIGGERED, accessCameraRoll);
			
			//Draw tab bar
			this.tabBar = new TabBar();
			tabBar.setSize((this.stage.stageWidth), (this.stage.stageHeight / 10));
			this.tabBar.dataProvider = new ListCollection(
			[
				{ label: "Edit" },
				{ label: "Upload" },
			]);
			this.tabBar.addEventListener(Event.CHANGE, tabBar_changeHandler);
			addChild(this.tabBar);
			this.tabBar.validate();
			this.tabBar.y = this.stage.stageHeight -this.tabBar.height;
			
			
		}
		
		/**
		 * Function to handle tab change events.
		 * @param	event
		 */
		private function tabBar_changeHandler(event:Event):void
		{
			if (statusChange)
			{
				statusChange = false;
				removeChild(statusLabel);
			}
			switch(tabBar.selectedIndex)
			{
				//Edit Tab
				case 0:
				{
					if (uploadContainerAdded)
					{
						removeChild(uploadContainer);
						uploadContainerAdded = false;
					}
					if (progressBarAdded)
					{
						removeChild(progressBar);
						removeChild(progressBarLabel);
						progressBarAdded = false;
					}
					break;
				}
				//Upload Tab
				case 1:
				{
					if (editConainerAdded)
					{
						removeChild(editContainer);
						editConainerAdded = false;
					}
					break;
				}
			}
			
			//Add choose image button
			if (!selectImageAdded)
			{
				selectImageAdded = true;
				addChild(selectImageButton);
			}
		}
		
		/**
		 * A function to dispatch an event when the back hardware key
		 * is pressed on android.
		 */
		private function backHandler():void
		{
			if (uploadContainerAdded)
			{	
				removeChild(uploadContainer);
				uploadContainerAdded = false;
			}
			if (editConainerAdded)
			{
				removeChild(editContainer);
				editConainerAdded = false;
			}
			if (progressBarAdded)
			{
				removeChild(progressBar);
				removeChild(progressBarLabel);
				progressBarAdded = false;
			}
			if (selectImageAdded)
			{
				selectImageAdded = false;
				removeChild(selectImageButton);
			}
			
			outcropArray = null;
			excursionArray = null;
			
			dispatchEvent(new NavigationEvent(NavigationEvent.RETURN));
		}
		
		/**
		 * A function to dispatch an event when the menu hardware key
		 * is pressed.
		 */
		private function menuHandler():void
		{
			if (uploadContainerAdded)
			{
				
				removeChild(uploadContainer);
				uploadContainerAdded = false;
			}
			if (editConainerAdded)
			{
				removeChild(editContainer);
				editConainerAdded = false;
			}
			
			dispatchEvent(new NavigationEvent(NavigationEvent.MAIN_MENU));
		}
		
		/**
		 * Draws the container object and its layout to be used for displaying the buttons
		 * associated with uploading images.
		 */
		private function drawUploadContainer():void
		{			
			var layout:VerticalLayout = new VerticalLayout();
			layout.paddingTop = 0.5*(this.stage.stageHeight / 8);
			layout.gap = 20;
			layout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_CENTER;
			layout.paddingTop = (this.stage.stageHeight / 10);
			layout.paddingBottom = (this.stage.stageHeight / 10);
			layout.hasVariableItemDimensions = true;
			
			uploadContainer = new ScrollContainer();
			uploadContainer.layout = layout;
			uploadContainer.scrollerProperties.horizontalScrollPolicy = Scroller.SCROLL_POLICY_OFF;
			uploadContainer.scrollerProperties.verticalScrollPolicy = Scroller.SCROLL_POLICY_AUTO;
			uploadContainer.scrollerProperties.snapScrollPositionsToPixels = true;
			uploadContainer.setSize(this.stage.stageWidth, 8 * (this.stage.stageHeight / 10));
			uploadContainer.y = (this.stage.stageHeight / 10);
		}
		
		/**
		 * Draws the container object and its layout to be used for displaying the buttons
		 * associated with editing images.
		 */
		private function drawEditContainer():void
		{
			var layout:VerticalLayout = new VerticalLayout();
			layout.paddingTop = 0.5*(this.stage.stageHeight / 8);
			layout.gap = 20;
			layout.horizontalAlign = VerticalLayout.HORIZONTAL_ALIGN_CENTER;
			layout.paddingTop = (this.stage.stageHeight / 10);
			layout.paddingBottom = (this.stage.stageHeight / 10);
			layout.hasVariableItemDimensions = true;
			
			editContainer = new ScrollContainer();
			editContainer.layout = layout;
			editContainer.scrollerProperties.horizontalScrollPolicy = Scroller.SCROLL_POLICY_OFF;
			editContainer.scrollerProperties.verticalScrollPolicy = Scroller.SCROLL_POLICY_AUTO;
			editContainer.scrollerProperties.snapScrollPositionsToPixels = true;
			editContainer.setSize(this.stage.stageWidth, 8 * (this.stage.stageHeight / 10));
			editContainer.y = (this.stage.stageHeight / 10);
		}
		
		/**
		 * Function to access the camera roll
		 * @param	event
		 */
		private function accessCameraRoll(event:Event):void
		{
			if (statusChange)
			{
				statusChange = false;
				removeChild(statusLabel);
			}
			
			var roll:CameraRoll;
			if (CameraRoll.supportsBrowseForImage)
			{
				roll = new CameraRoll();
				roll.addEventListener(MediaEvent.SELECT, onRollSelect);
				roll.addEventListener(Event.CANCEL, onRollCancel);
				roll.browseForImage();
			}
			else {
				statusLabel.text = "ERROR: This mobile does not \nsupport a required feature \nof this application.";
				addChild(statusLabel);
				statusChange = true;
			}
		}
		
		/**
		 * Function to handle the selection of an image through the camera roll.
		 * @param	event
		 */
		private function onRollSelect(event:MediaEvent):void
		{
			//Load the media promise
			imagePromise = event.data;
			var imgLoader:Loader = new Loader();
			
			//Check if selected image is in the database
			if (isInDatabase(imagePromise.file.nativePath))
			{
				//remove select button
				removeChild(selectImageButton);
				selectImageAdded = false;
				
				if(imagePromise.isAsync )
				{
					imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
					imgLoader.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
					imageNativePath = imagePromise.file.nativePath;
					imgLoader.loadFilePromise(imagePromise);				
				}
				else
				{
					imgLoader.loadFilePromise(imagePromise);
					imageNativePath = imagePromise.file.nativePath;
					drawImage(imgLoader);
				}
			}
			else
			{
				statusLabel.text = "This is not a geologise image file,\nplease try again";
				addChild(statusLabel);
				statusChange = true;
			}
		}
		
		/**
		 * Helper function to check if the chosen image has data in the database. All images
		 * will always have an entry in the database if they are taken using the geologise application.
		 * @param	imagePath the path to be searched for in the database
		 * @return
		 */
		private function isInDatabase(imagePath:String):Boolean
		{
			for (var i:int = 0; i < imageDatabaseData.length; i++)
			{
				if (imageDatabaseData[i].native_path == imagePath)
					return true;
			}
			return false;
		}
		
		/**
		 * Function to handle the drawing of the image after it has been loaded.
		 * @param	event
		 */
		private function onLoaded(event:Object):void
		{	
			var imgLoaderInfo:LoaderInfo = event.target as LoaderInfo;
			imgLoaderInfo.removeEventListener(Event.COMPLETE, onLoaded);
			imgLoaderInfo.loader.removeEventListener(IOErrorEvent.IO_ERROR, onLoadError);
			
			drawImage(imgLoaderInfo.loader);
		}
		
		/**
		 * Handles a load error that and displays an appropriate error message.
		 * @param	event
		 */
		private function onLoadError(event:IOErrorEvent):void
		{
			event.target.removeEventListener(IOErrorEvent.IO_ERROR, onLoadError);
			event.target.contentLoaderInfo.removeEventListener(Event.COMPLETE, onLoaded);
			
			statusLabel.text = "ERROR: Cannot load the image.";
			statusChange = true;
			addChild(statusLabel);
		}
		
		/**
		 * Draws the selected image.
		 */
		private function drawImage(imgLoader:Loader):void
		{
			var loadedBitmap:Bitmap = imgLoader.content as Bitmap;
			var image:Image = new Image(Texture.fromBitmap(resizeImage(loadedBitmap)))

			switch( this.tabBar.selectedIndex)
			{
				//Edit tab
				case 0:
				{
					editContainer.removeChildren(0, editContainer.numChildren, true);
					editContainer.addChild(image);
					this.addChild(editContainer);
					editConainerAdded = true;
					editContainer.validate();
					drawEditData();
					break;
				}
				//upload tab
				case 1:
				{
					uploadContainer.removeChildren(0, uploadContainer.numChildren, true);
					uploadContainer.addChild(image);
					this.addChild(uploadContainer);
					uploadContainerAdded = true;
					uploadContainer.validate();
					retrieveData();
					break;
				}
			}
		}
		
		/**
		 * Helper funtion to resize camera images so that they do not exceed the maximum
		 * size of textures.
		 * @param	image the images to be resized
		 * @return returns the resized bitmap
		 */
		private function resizeImage(image:Bitmap):Bitmap
		{
			var bigBMD:BitmapData = image.bitmapData;
			var size:int = 10 * (this.stage.stageWidth / 12);
			var scale:Number = Math.max(size / bigBMD.width, size / bigBMD.height);
			var matrix:Matrix = new Matrix();
			matrix.scale(scale, scale);

			var smallBMD:BitmapData = new BitmapData(bigBMD.width * scale, bigBMD.height * scale, true, 0x000000);
			smallBMD.draw(bigBMD, matrix, null, null, null, true);
			
			return new Bitmap(smallBMD, PixelSnapping.NEVER, true);
		}
		
		/**
		 * Retrieves the user token from the local database or notifies the controller
		 * that the user must log in.
		 */
		private function getUserToken():void
		{
			var tokenArray:Array = database.getToken();
			if (tokenArray != null)
			{
				this.token = database.getToken()[0].token;
				retrieveData();
			}
			else
			{
				removeChild(uploadContainer);
				uploadContainerAdded = false;
				dispatchEvent(new NavigationEvent(NavigationEvent.LOGING_REQUIRED));
			}
		}
		
		/**
		 * Retrieve data from the server using the stored authentication token.
		 */
		private function retrieveData():void
		{			
			if (token != null)
			{
				excursionLabel = new Label();
				excursionLabel.nameList.add(ExtendedMetalWorksMobileTheme.INPUT_LABEL);
				excursionLabel.text = "Loading data...";
				uploadContainer.addChild(excursionLabel);
				
				if (connection == null)
					connection = new ApiConnection();
				connection.setToken(token);

				if (excursionArray == null)
				{
					this.excursionArray = new Array();
					this.outcropArray = new Array();
					//Retrieve all of the excursions the user has been signed up for, this function returns the primary keys
					//of the excursions, another request must be made for the details of the excursion
					connection.getExcursions(excursionsLoadedHandler, statusHandler, securityHandler, IOErrorHandler);
				}
				else
					drawUploadData();
			}
			else
				getUserToken();
		}
		
		/**
		 * Callback function to process the data that hsa been loaded from the server.
		 * @param	event
		 */
		private function excursionsLoadedHandler(event:Object):void
		{
			var rawJSON:String = String(event.target.data);
			var array:Array = JSON.parse(rawJSON) as Array;
			//if null then only one element was returned
			if (array == null)
			{
				var json:Object = JSON.parse(rawJSON)
				excursionArray.push([json.id, json.name]);
			}
			else
			{
				for (var i:int = 0; i < array.length; i++)
				{
					excursionArray.push([array[i].id, array[i].name])
				}
			}
			getOutcropData();
		}
		
		/**
		 * Function to retrieve outcrop data from the server.
		 */
		private function getOutcropData():void
		{
			if (excursionIndex < excursionArray.length)
			{
				connection.getOutcrop(excursionArray[excursionIndex][0], outcropLoadedHandler, statusHandler, securityHandler, IOErrorHandler);
				currentExcursion = excursionArray[excursionIndex][0];
				excursionIndex++;
			}
			else
				drawUploadData();
		}
		
		/**
		 * Callback function to process the data loaded from the server.
		 * @param	event
		 */
		private function outcropLoadedHandler(event:Object):void
		{
			var rawJSON:String = String(event.target.data);
			var array:Array = JSON.parse(rawJSON) as Array;
			//if null then only one element was returned
			if (array == null)
			{
				var json:Object = JSON.parse(rawJSON)
				outcropArray.push([currentExcursion,json.id, json.name]);
			}
			else
			{
				for (var i:int = 0; i < array.length; i++)
				{
					outcropArray.push([currentExcursion, array[i].id, array[i].name])
				}
			}
			getOutcropData();	//call method recursively until all excursions have been processed.
		}
		
		/**
		 * Status handler, notifies the controller to ask the user to log in if the
		 * http status returned is 400.
		 * @param	event
		 */
		private function statusHandler(event:HTTPStatusEvent):void
		{
			if (event.status == 400)
				dispatchEvent(new NavigationEvent(NavigationEvent.LOGING_REQUIRED));
		}
		
		private function securityHandler(event:SecurityErrorEvent):void
		{
			trace("Security Error: "+event);
		}
		
		/**
		 * IOError handler, will most commonly be invoked because there is no
		 * internet connection.
		 * @param	event
		 */
		private function IOErrorHandler(event:IOErrorEvent):void
		{
			trace(event);
			statusLabel.text = "ERROR: Cannot connect\nto the internet.\n\n" +
				"Please check if your wireless\nor data connection is active.";
			statusChange = true;
			addChild(statusLabel);
			
			if (uploadContainerAdded)
			{
				uploadContainerAdded = false;
				removeChild(uploadContainer);
			}
		}
		
		/**
		 * Function to handle a cancel event from the camera roll
		 * @param	event
		 */
		private function onRollCancel(event:Object):void
		{
			//change back to edit mode
			tabBar.selectedIndex = 0;
		}
		
		/**
		 * Loads the file from the media promise in preparation for uploading the file.
		 */
		private function uploadFile():void
		{
			dataSource = imagePromise.open();
			
			//process the media promise to load the file from the media promise
			if (imagePromise.isAsync)
			{
				var eventSource:IEventDispatcher = dataSource as IEventDispatcher;
				eventSource.addEventListener(Event.COMPLETE, onFileLoaded);
			}
			else
				uploadFileData();
		}
		
		private function onFileLoaded(event:Object):void
		{
			uploadFileData();
		}
		
		/**
		 * Function to upload an image to the server along with all of the data associated
		 * with that image.
		 */
		private function uploadFileData():void
		{
			var imageBytes:ByteArray = new ByteArray();
			dataSource.readBytes(imageBytes);
			tempDir = File.createTempDirectory();
			
			var now:Date = new Date();
			var filename:String = "IMG" + now.fullYear + now.month + now.day + now.hours + now.minutes + now.seconds + ".jpg";
			var temp:File = tempDir.resolvePath( filename );
			
			var stream:FileStream = new FileStream();
			stream.open( temp, FileMode.WRITE );
			stream.writeBytes( imageBytes );
			stream.close();
			
			//Finding the associated metadata in the database
			var data:Object;
			for (var i:int = 0; i < imageDatabaseData.length; i++)
			{
				if (imageDatabaseData[i].native_path == imagePromise.file.nativePath)
				{
					data = imageDatabaseData[i];
					i = imageDatabaseData.length;
				}
			}
			
			var excursionID:int = excursionArray[excursionPicker.selectedIndex][0];
			
			var outcropID:int;
			if (outcropPicker.isEnabled)
			{
				outcropID = currentExcursionOutcrops[outcropPicker.selectedIndex][1];
				
				
				//outcropID = outcropArray[outcropPicker.selectedIndex][1];
			}
			else
				outcropID = -1;
			
			var tags:String = "";
			var tagArray:Array = database.readTagData(imageNativePath);
			for (var k:int = 0; k < tagArray.length; k++)
			{
				tags = tags + "," + tagArray[k].tag; 
			}

			connection.uploadImage(temp, excursionID, outcropID, tags, data.notes, data.altitude, data.longitude, data.latitude, data.heading, data.hAccuracy,
				data.vAccuracy, progressHandler, uploadCompleteHandler, statusHandler, securityHandler, IOErrorHandler);
			
			//Adding the progressBar
			progressBar = new ProgressBar();
			progressBar.minimum = 0;
			progressBar.maximum = 100;
			progressBar.value = 0;
			progressBar.setSize(this.stage.stageWidth-40, this.stage.stageHeight / 10);
			progressBar.y = this.stage.stageHeight / 2;
			progressBar.x = 20;
			
			progressBarLabel = new Label();
			progressBarLabel.x = this.stage.stageWidth - 80;
			progressBarLabel.y = (this.stage.stageHeight / 2) - 35;
			this.addChild(progressBarLabel);
			this.addChild(progressBar);
			progressBarAdded = true;
			removeChild(uploadContainer);
		}
		
		/**
		 * Callback function to update the progressbar.
		 * @param	event
		 */
		private function progressHandler(event:ProgressEvent):void
		{
			var percent:int =  event.bytesLoaded / event.bytesTotal * 100;
			this.progressBar.value = percent;
			this.progressBarLabel.text = percent + "%";
			this.progressBarLabel.validate();
		}
		
		/**
		 * Callback function for when the upload of a file completes.
		 * @param	event
		 */
		private function uploadCompleteHandler(event:Object):void
		{
			statusLabel.text = "Upload Completed.";
			addChild(statusLabel);
			statusChange = true;
			statusChange = true;
			//Cleanup
			removeTempDir();
		}
		
		/**
		 * Removes the temporary directory created when the file was loaded in preparation for
		 * its upload the server.
		 */
		private function removeTempDir():void
		{
			tempDir.deleteDirectory(true);
			tempDir = null;
		}
		
		/**
		 * Draws all of the data associated with uploading an image. This includes the outcrop
		 * and excursion pickers.
		 */
		private function drawUploadData():void
		{
			//Excursion label
			uploadContainer.removeChild(excursionLabel)
			excursionLabel.text = "Excursion:";
			excursionLabel.validate();
			uploadContainer.addChild(excursionLabel);	
			
			//The excursion picker
			excursionPicker = new PickerList();
			excursionPicker.setSize(10 * (this.stage.stageWidth / 12), (this.stage.stageHeight / 10));
			excursionItems = [];
			for(var i:int = 0; i < excursionArray.length; i++)
			{
				var item:Object = {text: " "+excursionArray[i][1]};
				excursionItems.push(item);
			}
			excursionItems.fixed = true;
			
			excursionPicker.dataProvider = new ListCollection(excursionItems);
			excursionPicker.typicalItem = {text: "Excursion"};
			excursionPicker.labelField = "text";
			uploadContainer.addChild(excursionPicker);

			excursionPicker.listProperties.typicalItem = {text: "Excursion"};
			excursionPicker.listProperties.@itemRendererProperties.labelField = ["text"];
			excursionPicker.addEventListener(Event.CHANGE, onExcursionPicker);
			
			if (excursionArray.length == 0)
			{
				excursionPicker.isEnabled = false;
				onExcursionPicker(new Event(Event.CHANGE));
			}
			
			if (excursionArray.length == 1)
				onExcursionPicker(new Event(Event.CHANGE));
			
			outcropPickerAdded = false;
		}
		
		/**
		 * Callback function to handle a change in the excursion picker.
		 * @param	event
		 */
		private function onExcursionPicker (event:Event):void
		{
			excursionPicker.itemToLabel(excursionItems[excursionPicker.selectedIndex]);
			
			if (!outcropPickerAdded)
			{
				//Outcrop label
				var outcropLabel:Label = new Label();
				outcropLabel.nameList.add(ExtendedMetalWorksMobileTheme.INPUT_LABEL);
				outcropLabel.text = "Outcrop:";
				uploadContainer.addChild(outcropLabel);
				
				//The outcrop picker
				outcropPicker = new PickerList();
				outcropPicker.setSize(10 * (this.stage.stageWidth / 12), (this.stage.stageHeight / 10));
			
				outcropItems = new Array();
				currentExcursionOutcrops = new Array();
				for(var i:int = 0; i < outcropArray.length; i++)
				{
					if (excursionArray[excursionPicker.selectedIndex][0] == outcropArray[i][0])
					{
						var item:Object = {text: " "+outcropArray[i][2]};
						outcropItems.push(item);
						currentExcursionOutcrops.push(outcropArray[i]);
					}
				}
				outcropItems.fixed = true;
				
				if (outcropItems.length > 0)
				{
					outcropPicker.isEnabled = true;
					outcropPicker.dataProvider = new ListCollection(outcropItems);
				}
				else
					outcropPicker.isEnabled = false;
					
				outcropPicker.typicalItem = {text: "Outcrop"};
				outcropPicker.labelField = "text";
				uploadContainer.addChild(outcropPicker);
				outcropPickerAdded = true;

				outcropPicker.listProperties.typicalItem = {text: "Outcrop"};
				outcropPicker.listProperties.@itemRendererProperties.labelField = "text";
				outcropPicker.addEventListener(Event.CHANGE, onOutcropPicker);
				
				//Add a blank label to create some padding between the upload button and the
				//last item picker
				var spaceLabel:Label = new Label();
				spaceLabel.text = "   ";
				spaceLabel.nameList.add(ExtendedMetalWorksMobileTheme.INPUT_LABEL);
				uploadContainer.addChild(spaceLabel);
				
				var uploadButton:Button = new Button();
				uploadButton.nameList.add(ExtendedMetalWorksMobileTheme.MENU_BUTTON);			
				uploadButton.label = "Upload";
				uploadButton.setSize(10 * (this.stage.stageWidth / 12), this.stage.stageHeight / 8);
				uploadButton.addEventListener(Event.TRIGGERED, uploadImages);
				uploadContainer.addChild(uploadButton);
				
				if (!excursionPicker.isEnabled)
					uploadButton.isEnabled = false;
			}
			else
			{
				outcropPicker.invalidate();
				
				outcropItems = new Array;
				for(var j:int = 0; j < outcropArray.length; j++)
				{
					if (excursionArray[excursionPicker.selectedIndex][0] == outcropArray[j][0])
					{
						var oItem:Object = {text: " "+outcropArray[j][2]};
						outcropItems.push(oItem);
					}
				}
				outcropItems.fixed = true;

				if (outcropItems.length > 0)
				{
					outcropPicker.isEnabled = true;
					outcropPicker.dataProvider = new ListCollection(outcropItems);
				}
				else
					outcropPicker.isEnabled = false;
				
				outcropPicker.validate();
			}
		}
		
		private function onOutcropPicker (event:Event):void
		{
			outcropPicker.itemToLabel(outcropItems[outcropPicker.selectedIndex]);
		}
		
		private function uploadImages(event:Event):void
		{
			uploadFile();
		}
		
		/**
		 * Draws the input fields and the buttons for the screen.
		 */
		private function drawEditData():void
		{	
			for (var i:int = 0; i < imageDatabaseData.length; i++)
			{
				if (imageDatabaseData[i].native_path == imagePromise.file.nativePath)
				{
					editData = imageDatabaseData[i];
					i = imageDatabaseData.length;
				}
			}
			
			var tagsData:Array = database.readTagData(imageNativePath);
			var tags:String = "";
			for (var j:int = 0; j < tagsData.length; j++)
			{
				if (tagsData[j].native_path == imagePromise.file.nativePath)
				{
					tags = tags +tagsData[j].tag+", ";
				}
			}
			
			//Tags
			var tagsLabel:Label = new Label();
			tagsLabel.text = "Tags (comma seperated):";
			tagsLabel.nameList.add(ExtendedMetalWorksMobileTheme.INPUT_LABEL);
			editContainer.addChild(tagsLabel);
			
			this.tagsIn = new TextInput();
			tagsIn.text = tags;
			tagsIn.setSize(10*(this.stage.stageWidth / 12), 1*(this.stage.stageHeight / 12));
			editContainer.addChild(tagsIn);
			tagsIn.validate();
			
			//Notes
			var notesLabel:Label = new Label();
			notesLabel.text = "Notes:";
			notesLabel.nameList.add(ExtendedMetalWorksMobileTheme.INPUT_LABEL);
			editContainer.addChild(notesLabel);
			
			this.notesIn = new TextInput();
			notesIn.text = editData.notes;
			notesIn.setSize(10*(this.stage.stageWidth / 12), 4*(this.stage.stageHeight / 12));
			editContainer.addChild(notesIn);
			notesIn.validate();
			
			notesIn.addEventListener(FeathersEventType.FOCUS_IN, onFocus);
			
			//Add a blank label to create some padding between the upload button and the
			//last item picker
			var spaceLabel:Label = new Label();
			spaceLabel.text = "   ";
			spaceLabel.nameList.add(ExtendedMetalWorksMobileTheme.INPUT_LABEL);
			editContainer.addChild(spaceLabel);
			
			var editButton:Button = new Button();
			editButton.nameList.add(ExtendedMetalWorksMobileTheme.MENU_BUTTON);			
			editButton.label = "Save";
			editButton.setSize(10 * (this.stage.stageWidth / 12), this.stage.stageHeight / 8);
			editButton.addEventListener(Event.TRIGGERED, onEditImage);
			editContainer.addChild(editButton);
		}
		
		/**
		 * Saves or updates the data associated with the image dependin on what mode
		 * the screen is operating in.
		 */
		private function onEditImage():void
		{
			database.updateImageData(editData.native_path, notesIn.text);
			database.deleteTagData(editData.native_path);
			
			var tags:Array = tagsIn.text.split(",");
			for (var i:int = 0; i < tags.length; i++)
				database.writeTagData(editData.native_path, tags[i]);
			
			//must requery db for new info and place it in the array
			imageDatabaseData = database.readImageData();	
				
			removeChild(editContainer);
			editConainerAdded = false;
				
			selectImageAdded = true;
			addChild(selectImageButton);
		}
		
		private function onFocus(event:Event):void
		{
			editContainer.validate();
			notesIn.validate();
		}
	}
}